#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */

#include <time.h> // to keep up a regular ping schedule, to keep the wireless module awake

int open_port(void) {
  int fd; /* File descriptor for the port */
  fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1) {      
    perror("open_port: Unable to open /dev/ttyUSB0 - ");
  }
  else {
    fcntl(fd, F_SETFL, FNDELAY);
  }
  return (fd);
}

// this is a variant fo write_to_port that will resend the message
// asap until it is successfully sent.
// assumes that it either writes everything, or nothing. Partways? Uh oh.
int will_succede_write(int fd, unsigned char* message, int mlength) {
  time_t start_time = time(NULL);
  time_t current_time;
  // the loop condition fails when the message is sent!
  while (write(fd, message, mlength) == -1) {
    current_time = time(NULL);
    if (difftime(current_time, start_time) > 1) {
      return 0; // it is taking over a second to send this message. Error?!
    }
  }
  tcflush(fd, TCOFLUSH);
  return 1; // sent message, all is well.
}

// the original write_to_port, with fewer nice wrappers
void write_to_port(int fd, unsigned char* message, int mlength) {
  int i;
  if ((i = write(fd, message, mlength)) != mlength) {
    printf("%i, Write failed!\n", i);
  }
  tcflush(fd, TCOFLUSH);
}

// this sends the "generic reply packet" or soomething like that
void send_generic_packet(int fd) {
  unsigned char msg[] = {0x05, 0x00, 0x00, 0x00, 0x01, 0xD0};
  will_succede_write(fd, msg, 6);
}

void send_generic_reply(int fd) {
  unsigned char msg[] = {0x05, 0x00, 0x00, 0x00, 0x01, 0xD1};
  will_succede_write(fd, msg, 6);
}

// this broadcasts a ping with a random board ID -- hope thats ok
int send_global_ping(int fd) {
  unsigned char ping_msg[] = {0x05, 0x00, 0x00, 0x00, 0x01, 0xA0};
  //  write_to_port(fd, ping_msg, 6);
  return will_succede_write(fd, ping_msg, 6);
  //return 0;
}

int send_random_noise(int fd) {
  static int noise = 12345;
  noise += 123;
  return will_succede_write(fd,(char*)noise, 2);
}

// this uses the new will_succede_write function, to ping the board itself.
int ping_board(int fd) {
  unsigned char ping_msg[] = {0x05, 0x00, 0x01, 0x00, 0x01, 0xA0};
  //write_to_port(fd, ping_msg, 6);
  return will_succede_write(fd, ping_msg,6); // trying out new write function;
  //return 0;
}

// the last byte specifies the memory location to read in.
void request_eeprom_read(int fd, unsigned char location) {
  unsigned char read_request[] = {0x06, 0x00, 0x01, 0x00, 0x01, 0xA8, 0x00};
  read_request[6] = location;
  write_to_port(fd, read_request, 7);
}

// requests board id.
void request_board_id(int fd) {
  unsigned char req_id_vec[] = {0x05, 0x00, 0x01, 0x00, 0x01, 0xB7}; // we know this works -- make sure board can reply. 
  write_to_port(fd, req_id_vec, 6);
}

// this changes the channel, I hope.
int set_trans_channel(int fd, unsigned char chan_num) {
  printf("%x\n", chan_num);
  unsigned char set_chan[] = {0x06, 0x00, 0x01, 0x00, 0x01, 0xA2, 0x00};
  set_chan[6] = chan_num;
  return will_succede_write(fd, set_chan, 7);
}

// this takes a time, and the wireless port. If the time is long ago enough to warrant a ping, it will ping.
// the function always returns the time it last pinged -- either the given time, or the the current time.
time_t wake_up_if_needed(int fd, time_t since_last_ping) {
  //static unsigned char chan = 0x00;
  time_t current_time = time(NULL);
  double num_seconds_passed = difftime(current_time, since_last_ping);
  if (num_seconds_passed > 1) {
    ping_board(fd);
    //set_trans_channel(fd, chan);
    //chan++;
    //chan %= 16;
    return current_time;
  }
  return since_last_ping;
}

// every time you call this function, it changes the channel. I hope.
int channel_surfer(int fd) {
  static unsigned char chan = 0x00;
  //set_trans_channel(fd, chan);
  chan++;
  chan %= 16;
  return set_trans_channel(fd, chan);
}

void assign_packet_source_and_dest(int source, int dest, char* packet) {
  packet[1] = (unsigned char)((dest&0xff00)>>8); // see rf1-z documentation; dest msb
  packet[2] = (unsigned char)(dest&0x00ff); // the dest lsb
  packet[3] = (unsigned char)((source&0xff00)>>8); // see rf1-z documentation; source msb
  packet[4] = (unsigned char)(source&0x00ff); // the source lsb
}

void set_port_settings(int fd) {
  struct termios options;
  fcntl(fd, F_SETFL, FNDELAY); // don't wait
  tcgetattr(fd, &options);
  cfsetispeed(&options, B9600); // set in and out speeds to 9600
  cfsetospeed(&options, B9600);
  options.c_cflag &= ~PARENB;
  options.c_cflag &= ~CSTOPB;
  options.c_cflag &= ~CSIZE;
  options.c_cflag |= CS8;		// parity to 8?
  
  options.c_oflag &= ~OPOST; // make output raw
  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make input raw
  tcsetattr(fd, TCSANOW, &options); // make this setting permanent.
}


int main(int argc, char* argv[]) {
  int fd, n, res;
  unsigned char get_all_channel_power[] = {0x05, 0x00, 0x01, 0x00, 0x01, 0xA5};
  unsigned char buf[255];
  int successes = 0;
  int i;
  fd = open_port();
  
  set_port_settings(fd);

  n = tcflush(fd, TCIOFLUSH);
  printf("Flushed: %i\n", n);
  
  // SETTING ARE NOW ASSIGNED.
  // NOW, HERE IS THE FUN STUFF
  time_t start_time = time(NULL);
  time_t end_time = time(NULL);
  time_t ping_time = time(NULL);
  int diag = 0;
  while(1){
  //while(difftime(end_time, start_time) < 10) {
    if (difftime(end_time, ping_time) > 1) {
      ping_time = time(NULL);
      fflush(stdout);
      send_generic_packet(fd);
      send_generic_packet(fd);
      printf("Sending packets %i and %i \r", diag, diag+1);
      diag += 2;
    }
    end_time = time(NULL); // update what time it is.
    //ping_time = wake_up_if_needed(fd, ping_time);
    //if (ping_board(fd)) { // count the number of successful pings.x
      //successes++;
      //}
    res = read(fd, buf, 255); // read the buffer, write what you see
    for( i = 0; i < res; i++) {
      printf("%x:", buf[i], res);
    }
    if (res > 0) {
      fflush(stdout);
      printf("\n"); // if you have something to write, write it
    }
  }
//fflush(stdout);
  //printf("%i", successes);
  close(fd);
}

